﻿using MediatR;
using Microsoft.EntityFrameworkCore;
using Ordering.Infrastructure;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ordering.Application.PipelineBehavior
{
    public class TransactionBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
        where TRequest : notnull
    {
        private readonly OrderingDbContext _context;

        public TransactionBehavior(OrderingDbContext context)
        {
            _context = context;
        }

        public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
        {
            TResponse? response = default;
            if (_context.HasActivedTransaction)
            {
                return await next();
            }
            var strategy = _context.Database.CreateExecutionStrategy();
            await strategy.ExecuteAsync(async () =>
            {
                using (var transaction = _context.BegionTransactionAsync(cancellationToken))
                {
                    try
                    {
                        response = await next();
                        await _context.CommitTransactionAsync(cancellationToken);
                    }
                    catch
                    {
                        await _context.RollbackTransactionAsync(cancellationToken);
                        throw;
                    }
                }
            });
            return response ?? throw new NullReferenceException();
        }
    }
}
